Headlines

AU_timeline %>% 
  # filter(date >= ymd(20200220)) %>% 
  arrange(date) %>% 
  add_row(date = ymd(20200120), event="") %>%
  # add_row(date = ymd(20200220), event="") %>%
  add_row(date = ymd(20200331), event="") %>%
  add_row(date = ymd(20200401), event="") %>%
  add_row(date = ymd(20200630), event="") %>%
  add_row(date = ymd(20200701), event="") %>%
  add_row(date = ymd(20200930), event="") %>%
  add_row(date = ymd(20201001), event="") %>%
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         point_position = 800 * nchar_scaled * (-1)^rowid,
         # point_position = c(100)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/2), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  facet_wrap(~facet_var, strip.position="top",
             ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Time series

Daily

confirmed_cases %>% 
  count(notification_date) %>% 
  ggplot(aes(x=notification_date , y=n)) + 
  # geom_point() + 
  geom_line() + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (NSW)") + 
  ggl()

confirmed_cases %>% 
  count(lhd_2010_name, notification_date) %>% 
  ggplot(aes(x=notification_date , y=n, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (NSW)") + 
  ggl(lp = "right")

Cumulative

confirmed_cases %>% 
  mutate(lhd_2010_name = ifelse(is.na(lhd_2010_name), "Unknown", lhd_2010_name)) %>%
  count(lhd_2010_name, notification_date) %>% 
  group_by(lhd_2010_name) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab = ifelse(notification_date == max(notification_date, na.rm=T), 
                      lhd_2010_name, NA)) %>% 
  
  ggplot(aes(x=days_since_first_case , y=accumulated_cases, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text_repel(aes(label=lab), size=3.3, hjust=-.1, min.segment.length = 10) + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Accumulated confirmed Covid-19 cases (NSW), by region") + 
  xlim(c(0,550)) +
  ggl(lp = "none")

confirmed_cases %>% 
  filter(lhd_2010_name %in% c("South Eastern Sydney", 
                           "Northern Sydney", 
                           "Western Sydney", 
                           "South Western Sydney", 
                           "Sydney") | is.na(lhd_2010_name)) %>% 
  count(lhd_2010_name, postcode, notification_date) %>% 
  group_by(lhd_2010_name, postcode) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab=ifelse(notification_date == max(notification_date), postcode, NA)) %>% 
  
  ggplot(aes(x=days_since_first_case , y=accumulated_cases, 
             group=postcode,
             col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text(aes(label=lab), size=3) + 
  facet_wrap(~lhd_2010_name, scales = "free_y") +
  labs(subtitle = "Accumulated confirmed Covid-19 cases (Sydney), by postcode") + 
  xlim(c(0,550)) +
  ggl(lp = "none", )

Map

Looks like each postcode (POA) can only belong to one LGA, which is not the case for SA2

confirmed_cases %>% 
  distinct(postcode, lga_name19) %>% 
  count(postcode) %>% 
  summarise(max(n)) %>% 
  pull()
[1] 1

LGA

confirmed_cases %>% 
  filter(lga_name19 %in% SYD_LGA$LGA_NAME19) %>% 
  count(lga_name19, name="Total_cases") %>% 
  rename(LGA_NAME19 = lga_name19) %>% 
  mutate(LGA_NAME19 = fct_reorder(LGA_NAME19, Total_cases)) %>% 
  plot_map_TL(SYD_LGA, "LGA_NAME19", "Total_cases", 
           "Total Covid-19 cases by LGA (SYD Metro)", show_count = T)

POA

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           show_count = T, label_size = 2)

confirmed_cases %>% 
  filter(!(postcode %in% c(2026, 2145, 2170))) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD Metro), excluding top 3 POA", 
           show_count = T, label_size = 2)

Note

Northern Beaches has many postcodes which result in more diluted choropleth by POA.

confirmed_cases %>% 
  distinct(lga_name19, postcode) %>% 
  count(lga_name19, name="Number_of_postcodes") %>% 
  left_join(confirmed_cases %>% count(lga_name19, name="Total_cases"), 
            by="lga_name19") %>% 
  slice_max(n=30, order_by = Total_cases) %>% 
  gather(key, value, -lga_name19) %>% 
  ggplot(aes(x=reorder(lga_name19, value), y=value)) + 
  geom_col() + 
  facet_wrap(~key, scales = "free_x") + 
  coord_flip() + 
  xlab("") + ylab("") + 
  ggl()

Map overtime cumulative

By quarter

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>% 
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_cases", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme(legend.position = "top")

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_share", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme(legend.position = "top")

By week Mar-May 2020

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_cases", 
              "Total Covid-19 cases by POA (SYD Metro)", 
              return_obj="map") + 
  facet_wrap(~facet_var)

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_share", 
              "Total Covid-19 cases by POA (SYD Metro)", 
              return_obj="map") + 
  facet_wrap(~facet_var)

Distribution of share overtime

By quarter

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  ungroup() %>% 
  
  ggplot(aes(x=year_quarter, y=Accumulated_cases, 
             fill=Accumulated_cases > 50,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(year_quarter))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~year_quarter, nrow = 1) + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

By week

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=isoweek, y=Accumulated_cases, 
             fill=Accumulated_cases > 20,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggx(round, pbn=12) +
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(isoweek))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~isoweek, nrow = 3, labeller = "label_both") + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

Local POI

Public transport

confirmed_cases %>% 
    filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
    count(postcode, name="Total_cases") %>% 
    rename(POA_NAME16 = postcode) %>% 
    mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
    plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
                "Total Covid-19 cases by POA (SYD Metro), with public transport", 
                show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.5) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.5) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.5) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.5) +
  ggc(c("darkblue", "red", "darkgreen", "orange")) + 
  guides(col=guide_legend(title="")) + 
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  coord_cartesian(xlim = c(150.7, 151.48), ylim = c(-34.1, -33.5)) +
  theme_void() +
  theme(legend.position = c(.9,.35))

Hospitals, Schools, Supermarket

bind_rows(
  SYD_shops %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
  SYD_supermarkets %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
  SYD_hospitals %>% select(Longitude, Latitude) %>% 
    rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
  rbind(SYD_sschools %>% select(Long, Lat),
        SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
) %>% 
  ggplot() +  
  geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
           aes(map_id = id), map = tidy(SYD_POA), 
           col="grey50", size=.2, fill="white") +
  geom_jitter(aes(x=Long, y=Lat, col=obj), size=.8, alpha=.5) + 
  stat_density2d(aes(x=Long, y=Lat, 
                     fill=..level.., alpha=..level.., col=obj),
                 binwidth = 1.2, geom="polygon", size=.23) + 
  facet_wrap(~obj) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "black", "darkgreen")) + 
  theme_void() +
  theme(legend.position = "none", 
        legend.title = element_blank(), 
        strip.text = element_text(size=15))

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
              "Total Covid-19 cases by POA (SYD Metro), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .3, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "darkorange", "darkgreen")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.25), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

POI combined

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
              "Total Covid-19 cases by POA (SYD Metro), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.5) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.5) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.5) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.5) +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .1, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "darkorange", "darkgreen", 
             "darkblue", "red", "darkgreen", "orange")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.4), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

LS0tDQp0aXRsZTogIlNZRCBDb3ZpZC0xOSBjYXNlcyBFREEiDQphdXRob3I6ICJUb255IExpdSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBzb3VyY2UoInV0aWxpdHkuUiIpDQpzb3VyY2UoIlJfZnVuY3Rpb25zLlIiKQ0Kc291cmNlKCJSX2RhdGFfcHJlcG9jZXNzaW5nLlIiKQ0KDQpvcHRpb25zKHNjaXBlbj05OTksIGV4cHJlc3Npb25zPTUwMDAwLCANCiAgICAgICAgRFQub3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDgsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFggPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9ucyA9IGMoJ2NvcHknLCAnY3N2JywgJ2V4Y2VsJywgJ3BkZicsICdwcmludCcpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0b1dpZHRoID0gVFJVRSkpIA0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFQsIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTQpDQprbml0cjo6b3B0c19rbml0JHNldChkZXYuYXJncyA9IGxpc3QodHlwZSA9ICJjYWlybyIpLCBwcm9ncmVzcz1GQUxTRSkNCmBgYA0KDQojIEhlYWRsaW5lcw0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTI1fQ0KQVVfdGltZWxpbmUgJT4lIA0KICAjIGZpbHRlcihkYXRlID49IHltZCgyMDIwMDIyMCkpICU+JSANCiAgYXJyYW5nZShkYXRlKSAlPiUgDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDEyMCksIGV2ZW50PSIiKSAlPiUNCiAgIyBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDAyMjApLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDMzMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwNDAxKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDA2MzApLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDcwMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwOTMwKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDEwMDEpLCBldmVudD0iIikgJT4lDQogICMgZmlsdGVyKG5jaGFyKGV2ZW50KSA8IDIzMCkgJT4lIA0KICAjIGZpbHRlcihyZWdpb24gIT0gIlZJQyIpICU+JSANCiAgbXV0YXRlKHJvd2lkID0gYXMubnVtZXJpYyhyb3duYW1lcyguKSkpICU+JSANCiAgbXV0YXRlKGRhdGVfZ2FwID0gYXMubnVtZXJpYyhkYXRlLWxhZyhkYXRlKSkpICU+JSANCiAgbXV0YXRlKG5jaGFyID0gbmNoYXIoZXZlbnQpLCANCiAgICAgICAgIG5jaGFyX3NjYWxlZCA9IChuY2hhci1taW4obmNoYXIpKS8obWF4KG5jaGFyKS1taW4obmNoYXIpKSwgDQogICAgICAgICBwb2ludF9wb3NpdGlvbiA9IDgwMCAqIG5jaGFyX3NjYWxlZCAqICgtMSlecm93aWQsDQogICAgICAgICAjIHBvaW50X3Bvc2l0aW9uID0gYygxMDApKigtMSlecm93aWQNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcXVhcnRlcihkYXRlLCB3aXRoX3llYXIgPSBUKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9MCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbD1yZWdpb24pKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1kYXRlLCB4ZW5kPWRhdGUsIGNvbD1yZWdpb24sDQogICAgICAgICAgICAgICAgICAgeT0wLCB5ZW5kPXBvaW50X3Bvc2l0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uKSwgc2hhcGU9MSkgKw0KICBnZW9tX3RleHQoYWVzKHk9LTEwLCANCiAgICAgICAgICAgICAgICBsYWJlbD1wYXN0ZTAoZGF5KGRhdGUpLCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb250aChkYXRlLCBsYWJlbD1UKSkpLCANCiAgICAgICAgICAgIGFuZ2xlPTMwLCANCiAgICAgICAgICAgIHZqdXN0PTEsIGhqdXN0PTEpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsPXN0cl93cmFwKHBhc3RlMChkYXRlLCAiOiAiLCBldmVudCksIG5jaGFyLzIpLCBhbHBoYT0uNywNCiAgICAgICAgICAgICAgICAgIyBkaXJlY3Rpb25zPSJ5IiwgbWluLnNlZ21lbnQubGVuZ3RoID0gSW5mLA0KICAgICAgICAgICAgICAgICB4PWRhdGUsIHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24sIHZqdXN0PSJvdXR3YXJkIikpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiViICVZIikgKyANCiAgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyLCBzdHJpcC5wb3NpdGlvbj0idG9wIiwNCiAgICAgICAgICAgICBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgIyBjb29yZF9mbGlwKCkgKw0KICB5bGltKC0xMjAwLDEyMDApICsgDQogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsgDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMjMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMi4zLCAwLCAyLjMpLCJjbSIpLA0KICAgICAgICAjIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTlVMTCkNCiAgICAgICAgKQ0KYGBgDQoNCg0KIyBUaW1lIHNlcmllcw0KIyMgRGFpbHkNCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTR9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBjb3VudChub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bm90aWZpY2F0aW9uX2RhdGUgLCB5PW4pKSArIA0KICAjIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkRhaWx5IG5ldyBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKE5TVykiKSArIA0KICBnZ2woKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgY291bnQobGhkXzIwMTBfbmFtZSwgbm90aWZpY2F0aW9uX2RhdGUpICU+JSANCiAgZ2dwbG90KGFlcyh4PW5vdGlmaWNhdGlvbl9kYXRlICwgeT1uLCBjb2w9bGhkXzIwMTBfbmFtZSkpICsgDQogICMgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fbGluZSgpICsgDQogICMgZmFjZXRfd3JhcCh+bGhkXzIwMTBfbmFtZSkgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJEYWlseSBuZXcgY29uZmlybWVkIENvdmlkLTE5IGNhc2VzIChOU1cpIikgKyANCiAgZ2dsKGxwID0gInJpZ2h0IikNCmBgYA0KDQojIyBDdW11bGF0aXZlDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgbXV0YXRlKGxoZF8yMDEwX25hbWUgPSBpZmVsc2UoaXMubmEobGhkXzIwMTBfbmFtZSksICJVbmtub3duIiwgbGhkXzIwMTBfbmFtZSkpICU+JQ0KICBjb3VudChsaGRfMjAxMF9uYW1lLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBncm91cF9ieShsaGRfMjAxMF9uYW1lKSAlPiUgDQogIG11dGF0ZShkYXlzX3NpbmNlX2ZpcnN0X2Nhc2UgPSBub3RpZmljYXRpb25fZGF0ZSAtIG1pbihub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgbXV0YXRlKGFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKG4pKSAlPiUgDQogIG11dGF0ZShsYWIgPSBpZmVsc2Uobm90aWZpY2F0aW9uX2RhdGUgPT0gbWF4KG5vdGlmaWNhdGlvbl9kYXRlLCBuYS5ybT1UKSwgDQogICAgICAgICAgICAgICAgICAgICAgbGhkXzIwMTBfbmFtZSwgTkEpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9ZGF5c19zaW5jZV9maXJzdF9jYXNlICwgeT1hY2N1bXVsYXRlZF9jYXNlcywgY29sPWxoZF8yMDEwX25hbWUpKSArIA0KICAjIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWxhYiksIHNpemU9My4zLCBoanVzdD0tLjEsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDEwKSArIA0KICAjIGZhY2V0X3dyYXAofmxoZF8yMDEwX25hbWUpICsgDQogIGxhYnMoc3VidGl0bGUgPSAiQWNjdW11bGF0ZWQgY29uZmlybWVkIENvdmlkLTE5IGNhc2VzIChOU1cpLCBieSByZWdpb24iKSArIA0KICB4bGltKGMoMCw1NTApKSArDQogIGdnbChscCA9ICJub25lIikNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9Nn0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihsaGRfMjAxMF9uYW1lICVpbiUgYygiU291dGggRWFzdGVybiBTeWRuZXkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3J0aGVybiBTeWRuZXkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZXN0ZXJuIFN5ZG5leSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNvdXRoIFdlc3Rlcm4gU3lkbmV5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiU3lkbmV5IikgfCBpcy5uYShsaGRfMjAxMF9uYW1lKSkgJT4lIA0KICBjb3VudChsaGRfMjAxMF9uYW1lLCBwb3N0Y29kZSwgbm90aWZpY2F0aW9uX2RhdGUpICU+JSANCiAgZ3JvdXBfYnkobGhkXzIwMTBfbmFtZSwgcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKGRheXNfc2luY2VfZmlyc3RfY2FzZSA9IG5vdGlmaWNhdGlvbl9kYXRlIC0gbWluKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBtdXRhdGUoYWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0obikpICU+JSANCiAgbXV0YXRlKGxhYj1pZmVsc2Uobm90aWZpY2F0aW9uX2RhdGUgPT0gbWF4KG5vdGlmaWNhdGlvbl9kYXRlKSwgcG9zdGNvZGUsIE5BKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRheXNfc2luY2VfZmlyc3RfY2FzZSAsIHk9YWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGdyb3VwPXBvc3Rjb2RlLA0KICAgICAgICAgICAgIGNvbD1saGRfMjAxMF9uYW1lKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1sYWIpLCBzaXplPTMpICsgDQogIGZhY2V0X3dyYXAofmxoZF8yMDEwX25hbWUsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnMoc3VidGl0bGUgPSAiQWNjdW11bGF0ZWQgY29uZmlybWVkIENvdmlkLTE5IGNhc2VzIChTeWRuZXkpLCBieSBwb3N0Y29kZSIpICsgDQogIHhsaW0oYygwLDU1MCkpICsNCiAgZ2dsKGxwID0gIm5vbmUiLCApDQpgYGANCg0KIyBNYXANCg0KTG9va3MgbGlrZSBlYWNoIHBvc3Rjb2RlIChQT0EpIGNhbiBvbmx5IGJlbG9uZyB0byBvbmUgTEdBLCB3aGljaCBpcyBub3QgdGhlIGNhc2UgZm9yIFNBMg0KDQpgYGB7cn0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGRpc3RpbmN0KHBvc3Rjb2RlLCBsZ2FfbmFtZTE5KSAlPiUgDQogIGNvdW50KHBvc3Rjb2RlKSAlPiUgDQogIHN1bW1hcmlzZShtYXgobikpICU+JSANCiAgcHVsbCgpDQpgYGANCg0KDQojIyBMR0ENCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGxnYV9uYW1lMTkgJWluJSBTWURfTEdBJExHQV9OQU1FMTkpICU+JSANCiAgY291bnQobGdhX25hbWUxOSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShMR0FfTkFNRTE5ID0gbGdhX25hbWUxOSkgJT4lIA0KICBtdXRhdGUoTEdBX05BTUUxOSA9IGZjdF9yZW9yZGVyKExHQV9OQU1FMTksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfTEdBLCAiTEdBX05BTUUxOSIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgTEdBIChTWUQgTWV0cm8pIiwgc2hvd19jb3VudCA9IFQpDQpgYGANCg0KIyMgUE9BDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMikNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKCEocG9zdGNvZGUgJWluJSBjKDIwMjYsIDIxNDUsIDIxNzApKSkgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pLCBleGNsdWRpbmcgdG9wIDMgUE9BIiwgDQogICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMikNCmBgYA0KDQojIyBOb3RlDQoNCk5vcnRoZXJuIEJlYWNoZXMgaGFzIG1hbnkgcG9zdGNvZGVzIHdoaWNoIHJlc3VsdCBpbiBtb3JlIGRpbHV0ZWQgY2hvcm9wbGV0aCBieSBQT0EuDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZGlzdGluY3QobGdhX25hbWUxOSwgcG9zdGNvZGUpICU+JSANCiAgY291bnQobGdhX25hbWUxOSwgbmFtZT0iTnVtYmVyX29mX3Bvc3Rjb2RlcyIpICU+JSANCiAgbGVmdF9qb2luKGNvbmZpcm1lZF9jYXNlcyAlPiUgY291bnQobGdhX25hbWUxOSwgbmFtZT0iVG90YWxfY2FzZXMiKSwgDQogICAgICAgICAgICBieT0ibGdhX25hbWUxOSIpICU+JSANCiAgc2xpY2VfbWF4KG49MzAsIG9yZGVyX2J5ID0gVG90YWxfY2FzZXMpICU+JSANCiAgZ2F0aGVyKGtleSwgdmFsdWUsIC1sZ2FfbmFtZTE5KSAlPiUgDQogIGdncGxvdChhZXMoeD1yZW9yZGVyKGxnYV9uYW1lMTksIHZhbHVlKSwgeT12YWx1ZSkpICsgDQogIGdlb21fY29sKCkgKyANCiAgZmFjZXRfd3JhcCh+a2V5LCBzY2FsZXMgPSAiZnJlZV94IikgKyANCiAgY29vcmRfZmxpcCgpICsgDQogIHhsYWIoIiIpICsgeWxhYigiIikgKyANCiAgZ2dsKCkNCmBgYA0KDQojIE1hcCBvdmVydGltZSBjdW11bGF0aXZlDQojIyBCeSBxdWFydGVyIHsudGFic2V0fQ0KIyMjIEFjY3VtdWxhdGVkIGNhc2VzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoeWVhcl9xdWFydGVyID0gcGFzdGUoeWVhcihub3RpZmljYXRpb25fZGF0ZSksICJRIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhcnRlcihub3RpZmljYXRpb25fZGF0ZSksIHNlcD0iLSIpKSAlPiUgDQogIGNvdW50KHllYXJfcXVhcnRlciwgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KHllYXJfcXVhcnRlcikgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSkpICU+JSANCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCh5ZWFyX3F1YXJ0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICANCiAgcGxvdF9tYXBfVEwocm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoDQogICAgU1lEX1BPQVtTWURfUE9BJFBPQV9OQU1FMTYgJWluJSBhcy5jaGFyYWN0ZXIoDQogICAgICBjb25maXJtZWRfY2FzZXMkcG9zdGNvZGUpICxdLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfY2FzZXMiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEIE1ldHJvKSIsIA0KICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQoNCiMjIyBBY2N1bXVsYXRlZCBzaGFyZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCh5ZWFyX3F1YXJ0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICANCiAgcGxvdF9tYXBfVEwocm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoDQogICAgU1lEX1BPQVtTWURfUE9BJFBPQV9OQU1FMTYgJWluJSBhcy5jaGFyYWN0ZXIoDQogICAgICBjb25maXJtZWRfY2FzZXMkcG9zdGNvZGUpICxdLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfc2hhcmUiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEIE1ldHJvKSIsIA0KICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQoNCiMjIEJ5IHdlZWsgTWFyLU1heSAyMDIwIHsudGFic2V0fQ0KIyMjIEFjY3VtdWxhdGVkIGNhc2VzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTEwfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgZmlsdGVyKHllYXIobm90aWZpY2F0aW9uX2RhdGUpID09IDIwMjAsIA0KICAgICAgICAgIyBtb250aChub3RpZmljYXRpb25fZGF0ZSkgJWluJSAzOjUsIA0KICAgICAgICAgaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkgJWluJSAxMDoyMykgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoaXNvd2VlayA9IGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIGNvdW50KGlzb3dlZWssIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoaXNvd2VlaywgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoaXNvd2VlaykgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSkpICU+JQ0KICBtdXRhdGUoZmFjZXRfdmFyID0gcGFzdGUwKCJ3ZWVrICIsIGlzb3dlZWssIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGZpbHRlcighaXMubmEoaXNvd2VlaykpICU+JSANCiAgDQogIHBsb3RfbWFwX1RMKHJtYXBzaGFwZXI6Om1zX3NpbXBsaWZ5KFNZRF9QT0EsIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9jYXNlcyIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgICAgIHJldHVybl9vYmo9Im1hcCIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3ZhcikNCmBgYA0KDQojIyMgQWNjdW11bGF0ZWQgc2hhcmUNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9MTB9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBmaWx0ZXIoeWVhcihub3RpZmljYXRpb25fZGF0ZSkgPT0gMjAyMCwgDQogICAgICAgICAjIG1vbnRoKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDM6NSwgDQogICAgICAgICBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDEwOjIzKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZShpc293ZWVrID0gaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgY291bnQoaXNvd2VlaywgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZShpc293ZWVrLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieShpc293ZWVrKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIG5hLnJtPVQpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGZpbHRlcighaXMubmEoaXNvd2VlaykpICU+JSANCiAgDQogIHBsb3RfbWFwX1RMKHJtYXBzaGFwZXI6Om1zX3NpbXBsaWZ5KFNZRF9QT0EsIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9zaGFyZSIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgICAgIHJldHVybl9vYmo9Im1hcCIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3ZhcikNCmBgYA0KDQojIERpc3RyaWJ1dGlvbiBvZiBzaGFyZSBvdmVydGltZQ0KIyMgQnkgcXVhcnRlcg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9My4zfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChBY2N1bXVsYXRlZF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD15ZWFyX3F1YXJ0ZXIsIHk9QWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGZpbGw9QWNjdW11bGF0ZWRfY2FzZXMgPiA1MCwNCiAgICAgICAgICAgICBncm91cD1hcy5mYWN0b3IoUE9BX05BTUUxNikpKSArIA0KICBnZW9tX2NvbChjb2w9IndoaXRlIiwgc2l6ZT0uMSkgKyANCiAgZ2dmKGZjID0gRENbMjoxXSkgKyANCiAgZ2dsKCJ0b3AiLCBsdCA9IFQpDQpgYGANCg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Mi41fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChBY2N1bXVsYXRlZF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1BY2N1bXVsYXRlZF9zaGFyZSwgZmlsbD1hcy5mYWN0b3IoeWVhcl9xdWFydGVyKSkpICsgDQogICMgZ2VvbV9kZW5zaXR5KCkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oKSArIA0KICBmYWNldF93cmFwKH55ZWFyX3F1YXJ0ZXIsIG5yb3cgPSAxKSArIA0KICB4bGltKDAsLjAzKSArIA0KICB5bGltKDAsNDApICsNCiAgZ2dsKCJub25lIikNCmBgYA0KDQojIyBCeSB3ZWVrDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zLjN9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBmaWx0ZXIoeWVhcihub3RpZmljYXRpb25fZGF0ZSkgPT0gMjAyMCwgDQogICAgICAgICAjIG1vbnRoKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDM6NSwgDQogICAgICAgICBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDEwOjIzKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZShpc293ZWVrID0gaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgY291bnQoaXNvd2VlaywgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZShpc293ZWVrLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieShpc293ZWVrKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpKSkgJT4lDQogIG11dGF0ZShmYWNldF92YXIgPSBwYXN0ZTAoIndlZWsgIiwgaXNvd2VlaywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuQWNjdW11bGF0ZWQ6ICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hKHN1bShBY2N1bXVsYXRlZF9jYXNlcykpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZmlsdGVyKCFpcy5uYShpc293ZWVrKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWlzb3dlZWssIHk9QWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGZpbGw9QWNjdW11bGF0ZWRfY2FzZXMgPiAyMCwNCiAgICAgICAgICAgICBncm91cD1hcy5mYWN0b3IoUE9BX05BTUUxNikpKSArIA0KICBnZW9tX2NvbChjb2w9IndoaXRlIiwgc2l6ZT0uMSkgKyANCiAgZ2d4KHJvdW5kLCBwYm49MTIpICsNCiAgZ2dmKGZjID0gRENbMjoxXSkgKyANCiAgZ2dsKCJ0b3AiLCBsdCA9IFQpDQpgYGANCg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NX0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGZpbHRlcih5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSA9PSAyMDIwLCANCiAgICAgICAgICMgbW9udGgobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMzo1LCANCiAgICAgICAgIGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMTA6MjMpICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKGlzb3dlZWsgPSBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBjb3VudChpc293ZWVrLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKGlzb3dlZWssIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KGlzb3dlZWspICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGlzb3dlZWspKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9QWNjdW11bGF0ZWRfc2hhcmUsIGZpbGw9YXMuZmFjdG9yKGlzb3dlZWspKSkgKyANCiAgIyBnZW9tX2RlbnNpdHkoKSArIA0KICBnZW9tX2hpc3RvZ3JhbSgpICsgDQogIGZhY2V0X3dyYXAofmlzb3dlZWssIG5yb3cgPSAzLCBsYWJlbGxlciA9ICJsYWJlbF9ib3RoIikgKyANCiAgeGxpbSgwLC4wMykgKyANCiAgeWxpbSgwLDQwKSArDQogIGdnbCgibm9uZSIpDQpgYGANCg0KIyBMb2NhbCBQT0kNCiMjIFB1YmxpYyB0cmFuc3BvcnQNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogICAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogICAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICAgIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCBNZXRybyksIHdpdGggcHVibGljIHRyYW5zcG9ydCIsIA0KICAgICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMiwgcmV0dXJuX29iaiA9ICJtYXAiKSArDQogIA0KICAjIGdlb21fbWFwKGluaGVyaXQuYWVzID0gRkFMU0UsIGFscGhhPS44NSwNCiAgIyAgICAgICAgICBhZXMobWFwX2lkID0gaWQpLCBtYXAgPSB0aWR5KFNZRF9QT0EpLCANCiAgIyAgICAgICAgICBjb2w9ImdyZXk1MCIsIHNpemU9LjMsIGZpbGw9IndoaXRlIikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF90cmFpbnMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJUcmFpbiIsDQogICAgICAgICAgICAgICAgZ3JvdXAgPSBgUmFpbHdheSBsaW5lKHMpYCksDQogICAgICAgICAgICBzaXplPS41KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX2ZlcnJpZXMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJGZXJyeSIpLA0KICAgICAgICAgICAgIHNpemU9LjUpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfbGlnaHRyYWlscywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9IkxpZ2h0cmFpbCIpLA0KICAgICAgICAgICAgIHNpemU9LjUpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfbWV0cm8sIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJNZXRybyIpLA0KICAgICAgICAgICAgIHNpemU9LjUpICsNCiAgZ2djKGMoImRhcmtibHVlIiwgInJlZCIsICJkYXJrZ3JlZW4iLCAib3JhbmdlIikpICsgDQogIGd1aWRlcyhjb2w9Z3VpZGVfbGVnZW5kKHRpdGxlPSIiKSkgKyANCiAgZXhwYW5kX2xpbWl0cyh4ID0gdGlkeShTWURfUE9BKSRsb25nLCB5ID0gdGlkeShTWURfUE9BKSRsYXQpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDE1MC43LCAxNTEuNDgpLCB5bGltID0gYygtMzQuMSwgLTMzLjUpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjksLjM1KSkNCmBgYA0KDQoNCiMjIEhvc3BpdGFscywgU2Nob29scywgU3VwZXJtYXJrZXQNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9OH0NCmJpbmRfcm93cygNCiAgU1lEX3Nob3BzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTaG9wcGluZyBjZW50cmVzIiksIA0KICBTWURfc3VwZXJtYXJrZXRzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTdXBlcm1hcmtldHMiKSwgDQogIFNZRF9ob3NwaXRhbHMgJT4lIHNlbGVjdChMb25naXR1ZGUsIExhdGl0dWRlKSAlPiUgDQogICAgcmVuYW1lKExvbmcgPSBMb25naXR1ZGUsIExhdCA9IExhdGl0dWRlKSAlPiUgbXV0YXRlKG9iaiA9ICJIb3NwaXRhbHMiKSwgDQogIHJiaW5kKFNZRF9zc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCksDQogICAgICAgIFNZRF9wc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCkpICU+JSBtdXRhdGUob2JqID0gIlNjaG9vbHMiKQ0KKSAlPiUgDQogIGdncGxvdCgpICsgIA0KICBnZW9tX21hcChkYXRhID0gU1lEX1BPQSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgYWxwaGE9Ljg1LA0KICAgICAgICAgICBhZXMobWFwX2lkID0gaWQpLCBtYXAgPSB0aWR5KFNZRF9QT0EpLCANCiAgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4yLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9qaXR0ZXIoYWVzKHg9TG9uZywgeT1MYXQsIGNvbD1vYmopLCBzaXplPS44LCBhbHBoYT0uNSkgKyANCiAgc3RhdF9kZW5zaXR5MmQoYWVzKHg9TG9uZywgeT1MYXQsIA0KICAgICAgICAgICAgICAgICAgICAgZmlsbD0uLmxldmVsLi4sIGFscGhhPS4ubGV2ZWwuLiwgY29sPW9iaiksDQogICAgICAgICAgICAgICAgIGJpbndpZHRoID0gMS4yLCBnZW9tPSJwb2x5Z29uIiwgc2l6ZT0uMjMpICsgDQogIGZhY2V0X3dyYXAofm9iaikgKw0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICB4bGltKDE1MC43LDE1MS40OCkgKyB5bGltKC0zNC4xLC0zMy41KSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ3aGl0ZSIsIGhpZ2g9RENbN10pICsgDQogIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsLjMpKSArIA0KICBnZ2MoZmMgPSBjKCJkYXJrcmVkIiwgImRhcmtibHVlIiwgImJsYWNrIiwgImRhcmtncmVlbiIpKSArIA0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pLCB3aXRoIGhvc3BpdGFscywgc2Nob29scyAmIHN1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgbGFiZWxfc2l6ZSA9IDIsIHJldHVybl9vYmogPSAibWFwIikgKw0KICANCiAgIyBnZW9tX21hcChkYXRhID0gU1lEX1BPQSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgYWxwaGE9Ljg1LA0KICAjICAgICAgICAgIGFlcyhtYXBfaWQgPSBpZCksIG1hcCA9IHRpZHkoU1lEX1BPQSksIA0KICAjICAgICAgICAgIGNvbD0iZ3JleTUwIiwgc2l6ZT0uMywgZmlsbD0id2hpdGUiKSArDQogIGdlb21faml0dGVyKGRhdGEgPSBiaW5kX3Jvd3MoDQogICAgU1lEX3Nob3BzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlNob3BwaW5nIGNlbnRyZXMiKSwgDQogICAgU1lEX3N1cGVybWFya2V0cyAlPiUgc2VsZWN0KGxvbiwgbGF0KSAlPiUgDQogICAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTdXBlcm1hcmtldHMiKSwgDQogICAgU1lEX2hvc3BpdGFscyAlPiUgc2VsZWN0KExvbmdpdHVkZSwgTGF0aXR1ZGUpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gTG9uZ2l0dWRlLCBMYXQgPSBMYXRpdHVkZSkgJT4lIG11dGF0ZShvYmogPSAiSG9zcGl0YWxzIiksIA0KICAgIHJiaW5kKFNZRF9zc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCksDQogICAgICAgICAgU1lEX3BzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSkgJT4lIG11dGF0ZShvYmogPSAiU2Nob29scyIpDQogICksIA0KICBzaXplID0gMSwgYWxwaGEgPSAuMywgYWVzKHg9TG9uZywgeT1MYXQsY29sPW9iaikpICsNCiAgZXhwYW5kX2xpbWl0cyh4ID0gdGlkeShTWURfUE9BKSRsb25nLCB5ID0gdGlkeShTWURfUE9BKSRsYXQpICsNCiAgeGxpbSgxNTAuNywxNTEuNDgpICsgeWxpbSgtMzQuMSwtMzMuNSkgKw0KICAjIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ3aGl0ZSIsIGhpZ2g9RENbN10pICsgDQogIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsLjMpKSArIA0KICBnZ2MoZmMgPSBjKCJkYXJrcmVkIiwgImRhcmtibHVlIiwgImRhcmtvcmFuZ2UiLCAiZGFya2dyZWVuIikpICsgDQogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9IlBPSSIpKSArIA0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC45LC4yNSksIA0KICAgICAgICAjIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSkpDQpgYGANCiMjIFBPSSBjb21iaW5lZA0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQocG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgcGxvdF9tYXBfVEwoU1lEX1BPQSwgIlBPQV9OQU1FMTYiLCAiVG90YWxfY2FzZXMiLCANCiAgICAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEIE1ldHJvKSwgd2l0aCBob3NwaXRhbHMsIHNjaG9vbHMgJiBzdXBlcm1hcmtldHMiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyLCByZXR1cm5fb2JqID0gIm1hcCIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfdHJhaW5zLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iVHJhaW4iLA0KICAgICAgICAgICAgICAgIGdyb3VwID0gYFJhaWx3YXkgbGluZShzKWApLA0KICAgICAgICAgICAgc2l6ZT0uNSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF9mZXJyaWVzLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iRmVycnkiKSwNCiAgICAgICAgICAgICBzaXplPS41KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX2xpZ2h0cmFpbHMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJMaWdodHJhaWwiKSwNCiAgICAgICAgICAgICBzaXplPS41KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX21ldHJvLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iTWV0cm8iKSwNCiAgICAgICAgICAgICBzaXplPS41KSArDQogIA0KICAjIGdlb21fbWFwKGRhdGEgPSBTWURfUE9BLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBhbHBoYT0uODUsDQogICMgICAgICAgICAgYWVzKG1hcF9pZCA9IGlkKSwgbWFwID0gdGlkeShTWURfUE9BKSwgDQogICMgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4zLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGJpbmRfcm93cygNCiAgICBTWURfc2hvcHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU2hvcHBpbmcgY2VudHJlcyIpLCANCiAgICBTWURfc3VwZXJtYXJrZXRzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlN1cGVybWFya2V0cyIpLCANCiAgICBTWURfaG9zcGl0YWxzICU+JSBzZWxlY3QoTG9uZ2l0dWRlLCBMYXRpdHVkZSkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBMb25naXR1ZGUsIExhdCA9IExhdGl0dWRlKSAlPiUgbXV0YXRlKG9iaiA9ICJIb3NwaXRhbHMiKSwgDQogICAgcmJpbmQoU1lEX3NzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSwNCiAgICAgICAgICBTWURfcHNjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpKSAlPiUgbXV0YXRlKG9iaiA9ICJTY2hvb2xzIikNCiAgKSwgDQogIHNpemUgPSAxLCBhbHBoYSA9IC4xLCBhZXMoeD1Mb25nLCB5PUxhdCxjb2w9b2JqKSkgKw0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICB4bGltKDE1MC43LDE1MS40OCkgKyB5bGltKC0zNC4xLC0zMy41KSArDQogICMgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD1EQ1s3XSkgKyANCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoMCwuMykpICsgDQogIGdnYyhmYyA9IGMoImRhcmtyZWQiLCAiZGFya2JsdWUiLCAiZGFya29yYW5nZSIsICJkYXJrZ3JlZW4iLCANCiAgICAgICAgICAgICAiZGFya2JsdWUiLCAicmVkIiwgImRhcmtncmVlbiIsICJvcmFuZ2UiKSkgKyANCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0zKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iUE9JIikpICsgDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjksLjQpLCANCiAgICAgICAgIyBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==